package com.bilibili.filter;

import com.bilibili.dto.JsonResult;
import com.bilibili.entity.User;
import com.bilibili.utils.WebOperations;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;

/**
 * 用于专门对项目中的访问的路径进行鉴权的过滤器
 * 对于项目中那些必须基于登录状态才能访问的路径，在这里直接处理后提示用户请先登录
 * 对于那些可以在不登录情况下访问的路径直接放行即可
 */
public class SessionFilter implements Filter {
    private List<String> sessionInterceptorUrls;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //读取用于保存那些需要被拦截的路径的文件
        try (InputStream is = SessionFilter.class.getClassLoader().getResourceAsStream(filterConfig.getInitParameter("sessionInterceptorUrlFilePath"))) {
            sessionInterceptorUrls = IOUtils.readLines(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse res = (HttpServletResponse) servletResponse;
        //（1）判断当前的请求路径是否为那些需要基于登录才能访问的路径，如果是
        String uri = req.getRequestURI();
        boolean needLogin = false;
        for (String pattern : sessionInterceptorUrls) {
            boolean matched = new AntPathMatcher().match(pattern, uri);
            if (matched) {
                needLogin = true;
                break;
            }
        }
        if (needLogin) {
            //获取用户的登录状态
            //因为Filter不是SpringBean，所以在这里要使用Bean对象，可以先去获取容器对象
            ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(req.getSession().getServletContext());
            WebOperations webOperations = ac.getBean(WebOperations.class);
            User loginUser = webOperations.getLoginUser(req);
            //（1-1）未登录状态下提示尚未登录
            if (Objects.isNull(loginUser)) {
                res.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                PrintWriter pw = res.getWriter();
                JsonResult result = new JsonResult();
                int code = HttpStatus.UNAUTHORIZED.value();
                result.setCode(code).setError("用户尚未登录");
                res.setStatus(code);
                pw.print(new ObjectMapper().writeValueAsString(result));
            }
            //（1-2）登录状态下直接放行
            else {
                filterChain.doFilter(req, res);
            }
        }
        //（2）不是那些需要基于登录才能访问的路径
        else {
            //直接放行
            filterChain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {

    }
}
